#pragma once
#include <iostream>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string>
#include <errno.h>
#include <cstring>
#include <cstdio>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <pthread.h>
#include <memory>
#include "log.hpp"
#include "Thread_Pool.hpp"
#include "Task.hpp"
using namespace std;

static void service(int socket, string ip, uint16_t port)
{
    char buffer[1024];
    while (1)
    {
        ssize_t s = read(socket, buffer, sizeof buffer - 1);
        if (s > 0) // 正常读取
        {
            buffer[s] = '\0';
            printf("[%s][%d]:%s\n", ip.c_str(), port, buffer);
        }
        else if (s == 0) // 说明客户端关闭了描述符
        {
            logMassage(NORMAL, "客户端[%s][%d]关闭通信\n", ip, port);
            break;
        }
        else // 说明读取出错
        {
            logMassage(ERROR,"客户端[%s][%d]读取出错\n", ip, port);
            break;
        }
        write(socket,buffer,strlen(buffer));
    }
}

//version 3.0
// class ThreadData
// {
// public:
//     int _sock;
//     struct sockaddr_in sockaddr_indata;
// };

class tcp_sever
{
private:
    const static int gbacklog = 20;
    //version 3.0
    // static void* threadroutine(void* args)
    // {
    //     char buffer[1024];
    //     pthread_detach(pthread_self());
    //     ThreadData* td = (ThreadData*)args;
    //     while(1)
    //     {
    //         ssize_t s = recv(td->_sock,buffer,sizeof buffer - 1,0);
    //         if(s > 0)//说明正常读取
    //         {
    //             buffer[s] = '\0';
    //             //printf("[%s][%d]:%s\n", ip.c_str(), port, buffer);
    //             printf("[%s][%d]:%s\n", inet_ntoa(td->sockaddr_indata.sin_addr), ntohs(td->sockaddr_indata.sin_port), buffer);
    //         }
    //         else if(s == 0)//说明客户端关闭了
    //         {
    //             logMassage(NORMAL,"客户端[%s][%d]关闭\n",inet_ntoa(td->sockaddr_indata.sin_addr), ntohs(td->sockaddr_indata.sin_port));
    //             break;
    //         }
    //         else//说明读取出错了
    //         {
    //             logMassage(NORMAL,"客户端[%s][%d]读取出错\n",inet_ntoa(td->sockaddr_indata.sin_addr), ntohs(td->sockaddr_indata.sin_port));
    //             break;
    //         }
    //         send(td->_sock,buffer,strlen(buffer),0);
    //     }
    //     delete td;
    //     return nullptr;
    // }
    
public:
    tcp_sever(uint16_t port, string ip = "")
        : _port(port), _ip(ip), _listensocket(-1),_tp(ThreadPool<Task>::GetThreadpool())
    {
    }
    void severinit()
    {
        // 第一步：创建套接字
        _listensocket = socket(AF_INET, SOCK_STREAM, 0);
        if (_listensocket < 0)
        {
            logMassage(FATAL, "创建套接字失败：%d : %s\n", errno, strerror(errno));
            exit(2);
        }
        // 第二步：绑定
        struct sockaddr_in local;
        memset(&local, 0, sizeof local);
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = _ip.empty() ? INADDR_ANY : inet_addr(_ip.c_str());
        if (bind(_listensocket, (struct sockaddr *)&local, sizeof local) < 0)
        {
            logMassage(FATAL, "绑定失败%d : %s\n", errno, strerror(errno));
            exit(3);
        }

        // 第三步：开始监听
        if (listen(_listensocket, gbacklog) < 0)
        {
            logMassage(FATAL, "监听失败%d : %s\n", errno, strerror(errno));
            exit(4);
        }
        logMassage(NORMAL, "初始化服务器成功\n");
    }
    void severstart()
    {
        //version 2.0
        //signal(SIGCHLD,SIG_IGN);

        //version 4.0
        cout<<"准备开启线程"<<endl;
        _tp->run();
        cout<<"开启线程完成"<<endl;
        while (1)
        {
            // 试图建立连接
            struct sockaddr_in src;
            socklen_t len = sizeof src;
            logMassage(NORMAL,"正在准备建立连接···\n");
            int servicesocket = accept(_listensocket, (struct sockaddr *)&src, &len);
            if (servicesocket < 0)
            {
                logMassage(ERROR, "%d : %s\n", errno, strerror(errno));
                continue;
            }
            
            // 走到这里说明建立连接成功
            // 可以开始进行通信了
            uint16_t port = htons(src.sin_port);
            string ip = inet_ntoa(src.sin_addr);
            cout<<ip<<endl;
            logMassage(NORMAL, "建立连接成功,客户端ip:%s,端口号:%d\n", ip.c_str(), port);



            //version 4.0 线程池版本
            Task t(servicesocket,ip,port,service);//sock ip 端口 回调
            _tp->pushTask(t);
            // version 1 单进程版本
            //service(servicesocket, ip, port);


            //version 2.0 多进程版本
            // pid_t pid = fork();
            // assert(pid != -1);
            // if(pid == 0)//子进程
            // {
            //     close(_listensocket);
            //     service(servicesocket, ip, port);
            //     exit(0);
            // }
            // close(servicesocket);


            //version 2.0.1 多进程版本--另一种方案 子进程创建出来之后，再由子进程创建孙子进程，然后令子进程退出，用父进程回收子进程 这样孙子进程就成为了孤儿进程 孤儿进程会交给操作系统自行回收
            // pid_t id = fork();
            // if(id == 0)//子进程
            // {
            //     if(fork() == 0)//孙子进程
            //     {
            //         close(_listensocket);
            //         service(servicesocket, ip, port);
            //     }
            //     exit(0);//这里子进程正常退出，由父进程回收
            // }
            // //父进程
            // close(servicesocket);
            // waitpid(id,nullptr,0);


            //version 3.0 多线程版本
            // pthread_t tid;
            // //unique_ptr<ThreadData> td(new ThreadData);
            // ThreadData* td = new ThreadData;
            // memset(td,0,sizeof(ThreadData));
            // td->_sock = servicesocket;
            // td->sockaddr_indata.sin_family = AF_INET;
            // td->sockaddr_indata.sin_port = src.sin_port;
            // td->sockaddr_indata.sin_addr.s_addr = src.sin_addr.s_addr;
            // pthread_create(&tid,nullptr,threadroutine,(void*)td);
            // close(_listensocket);

            
            
            
        }
    }
    ~tcp_sever()
    {
    }

private:
    uint16_t _port;
    string _ip;
    int _listensocket;
    unique_ptr<ThreadPool<Task>> _tp;
};